/*
 * RoadSegment.cpp
 *
 *  Created on: Oct 25, 2009
 *      Author: jbarreneche
 */

#include <cmath>
#include "RoadSegment.h"

void orderMinMax(int *min, int *max) {
	if (*min > *max) {
		*min ^= *max;
		*max ^= *min;
		*min ^= *max;
	}
}
RoadSegment::RoadSegment(Road* road, int minHeight, int maxHeight,
		Intersection *origin, Intersection *destination) {
	this->road = road;
	bool inverted = minHeight > maxHeight;
	this->maxHeight = inverted ? minHeight : maxHeight;
	this->minHeight = inverted ? maxHeight : minHeight;
	this->origin = inverted ? destination : origin;
	this->destination = inverted ? origin : destination;
	origin->intersect(this);
	destination->intersect(this);
	this->maxSpeedAllowed = 99999; // High value.
	this->length = 0; // Low Value
}

RoadSegment::~RoadSegment() { }

void RoadSegment::addEdge(Edge* edge, bool increasingDirection) {
	if (increasingDirection)
		this->increasingEdges.add(0, edge);
	else
		this->decreasingEdges.add(0, edge);
	// Por las dudas guardo la menor de las velocidades permitidas.
	this->maxSpeedAllowed = min(edge->getSpeedInKMH(), this->maxSpeedAllowed);
	this->length = max(this->length, edge->getDistanceInMeters());
}
util::LinkedList<Edge> RoadSegment::getIncreasingEdges() {
	return this->increasingEdges;
}

util::LinkedList<Edge> RoadSegment::getDecreasingEdges() {
	return this->decreasingEdges;
}

bool RoadSegment::overlaps(int minHeight, int maxHeight) {
	orderMinMax(&minHeight, &maxHeight);
	return this->minHeight < maxHeight && this->maxHeight > minHeight;
}

bool RoadSegment::overlapsExactly(int minHeight, int maxHeight) {
	orderMinMax(&minHeight, &maxHeight);
	return this->minHeight == minHeight && this->maxHeight == maxHeight;
}
MapPoint RoadSegment::getPointAt(int height) {
	double percentage = this->increasingPercentage(height);
	double x = (this->destination->getX() - this->origin->getX()) * percentage + this->origin->getX();
	double y = (this->destination->getY() - this->origin->getY()) * percentage + this->origin->getY();
	return MapPoint(x, y);
}
double RoadSegment::getHeightForDelta(double currentHeight, double deltaInMeters) {
	double percentage = (currentHeight - this->minHeight) / (this->maxHeight - this->minHeight);
	double deltaPercentage = deltaInMeters / this->length;
	double finalPercentage = min(1.0, max(0.0, percentage + deltaPercentage));
	return (finalPercentage * (this->maxHeight - this->minHeight) + this->minHeight);
}
Intersection* RoadSegment::getIntersectionFor(MapPoint point) {
	if (point == *this->origin) {
		return this->origin;
	} else {
		return this->destination;
	}

}

bool RoadSegment::contains(int height) {
	return height >= minHeight && height <= maxHeight;
}

double RoadSegment::increasingPercentage(int height) {
	return (double) (height - minHeight) / (maxHeight - minHeight);
}
double RoadSegment::decreasingPercentage(int height) {
	return 1 - increasingPercentage(height);
}

int RoadSegment::getHeightFor(Intersection* intersection) {
	return (intersection == this->getOrigin())? this->minHeight + 1 : this->maxHeight - 1;
}
